package sk.uniba.fmph.asdf.gui.frames;

import com.alee.extended.filechooser.SelectionMode;
import com.alee.extended.filechooser.WebFileChooser;
import com.alee.laf.GlobalConstants;
import com.alee.laf.StyleConstants;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeSelectionModel;
import sk.uniba.fmph.asdf.Exporter;
import sk.uniba.fmph.asdf.Session;
import sk.uniba.fmph.asdf.db.FullName;
import sk.uniba.fmph.asdf.exceptions.DatabaseException;
import sk.uniba.fmph.asdf.exceptions.PermissionDeniedException;
import sk.uniba.fmph.asdf.tempt.TestTemplate;
import sk.uniba.fmph.asdf.test.TestResult;
import com.jcraft.jsch.JSchException;
import java.util.logging.Level;
import java.util.logging.Logger;
import sk.uniba.fmph.asdf.exceptions.OfflineException;
import sk.uniba.fmph.asdf.gui.views.MainView;

/**
 *
 * @author Jakub Gaľ
 */
public class ExportFrame extends Frame implements TreeSelectionListener, MouseListener {

	private static final long serialVersionUID = 8137954790949269592L;
	private TestTemplate actualTestTemplate;
	private TestResult actualTestResult;
	private javax.swing.JButton buttonDumpDatabase;
	private javax.swing.JButton buttonExportField;
	private javax.swing.JButton buttonExportLogs;
	private javax.swing.JButton buttonExportTest;
	private javax.swing.JPanel panelCenter;
	private javax.swing.JPanel panelLeft;
	private javax.swing.JPanel panelRight;
	private javax.swing.JTable resultsTable;
	private javax.swing.JScrollPane scrollPaneTestPreview;
	private javax.swing.JScrollPane scrollPaneTests;
	private javax.swing.JTree treeTests;
	private static final int ADDITIONAL_COLUMNS = 3;
	private static final String ERROR_TITLE = "Chyba";
	private static final String INFO_TITLE = "Správa";
	private static final String PERMISSION_EXCEPTION_MSG =
					"Nedostatočné oprávnenia.";
	private static final String IO_EXCEPTION_MSG =
					"Nastala chyba počas čítania alebo zapisovania súboru";
	private static final String DB_EXCEPTION_MSG =
					"Nastala chyba komunikácie s databázou.";

    private WebFileChooser wfc;

	/**
	 * Creates new form evaluationView
	 */
	public ExportFrame(MainView parent) {
		super(parent);
		initComponents();
        wfc = new WebFileChooser(parent);
				wfc.setCurrentDirectory(System.getProperty("user.home"));
        wfc.setSelectionMode(SelectionMode.SINGLE_SELECTION);
        wfc.setAvailableFilter(GlobalConstants.FILES_FILTER);
        wfc.setChooseFilter(GlobalConstants.FILES_FILTER);
	}

	@Override
	public void onShow() {
//		parent.setSubtitle("Export údajov");
	}

	/**
	 * Inicializuje komponenty.
	 */
	private void initComponents() {

		setMinimumSize(new java.awt.Dimension(800, 600));
		setPreferredSize(new java.awt.Dimension(800, 600));
		setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.LINE_AXIS));

		panelLeft = new javax.swing.JPanel();
		scrollPaneTests = new javax.swing.JScrollPane();
		treeTests = new javax.swing.JTree();
		panelCenter = new javax.swing.JPanel();
		scrollPaneTestPreview = new javax.swing.JScrollPane();
		resultsTable = new javax.swing.JTable();
		panelRight = new javax.swing.JPanel();
		buttonExportTest = new javax.swing.JButton();
		buttonExportField = new javax.swing.JButton();
		buttonDumpDatabase = new javax.swing.JButton();
		buttonExportLogs = new javax.swing.JButton();

		panelLeft.setPreferredSize(new java.awt.Dimension(175, 600));
		panelLeft.setMaximumSize(new java.awt.Dimension(175, Integer.MAX_VALUE));
		panelLeft.setLayout(new javax.swing.BoxLayout(panelLeft, javax.swing.BoxLayout.PAGE_AXIS));

		generateTestTree();
		treeTests.addTreeSelectionListener(this);
		scrollPaneTests.setViewportView(treeTests);

		panelLeft.add(scrollPaneTests);

		add(panelLeft);

		panelCenter.setBorder(javax.swing.BorderFactory.createEtchedBorder());
		panelCenter.setPreferredSize(new java.awt.Dimension(450, 600));
		panelCenter.setLayout(new java.awt.BorderLayout());

		resultsTable.setModel(new javax.swing.table.DefaultTableModel(
						new Object[][]{},
						new String[]{"Hodnotiteľ", "Študent", "Spolu"}));
		scrollPaneTestPreview.setViewportView(resultsTable);

		panelCenter.add(scrollPaneTestPreview, java.awt.BorderLayout.CENTER);

		add(panelCenter);

		panelRight.setMaximumSize(new java.awt.Dimension(175, Integer.MAX_VALUE));
		panelRight.setPreferredSize(new java.awt.Dimension(175, 600));
		panelRight.setLayout(new java.awt.GridLayout(0, 1));

		buttonExportTest.setText("Exportuj test");
		buttonExportTest.addMouseListener(this);

		buttonExportField.setText("Exportuj field");
		buttonExportField.addMouseListener(this);

		buttonDumpDatabase.setText("Exportuj DB");
		buttonDumpDatabase.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {

				if (!Session.getAccount().isAdmin()) {
					JOptionPane.showMessageDialog(parent,
									PERMISSION_EXCEPTION_MSG, ERROR_TITLE,
									JOptionPane.ERROR_MESSAGE);
					return;
				}
					try {
						Exporter.exportDatabase();
                        JOptionPane.showMessageDialog(parent,
									"Databáza bola exportovaná.", INFO_TITLE,
									JOptionPane.INFORMATION_MESSAGE);
					} catch (PermissionDeniedException | JSchException | IOException exception) {
						exception.printStackTrace();
					}

				}

		});

		buttonExportLogs.setText("Exportuj logy");
		buttonExportLogs.addMouseListener(this);

		panelRight.add(buttonExportTest);
		panelRight.add(buttonExportField);
		panelRight.add(buttonExportLogs);
		panelRight.add(buttonDumpDatabase);

		add(panelRight);
	}

	// Code for dispatching events from components to event handlers.
	@Override
	public void mouseClicked(java.awt.event.MouseEvent evt) {
		if (evt.getSource() == buttonExportTest) {
			this.buttonExportTestMouseClicked(evt);
		} else if (evt.getSource() == buttonExportField) {
			this.buttonExportFieldMouseClicked(evt);
		} else if (evt.getSource() == buttonExportLogs) {
			this.buttonExportLogsMouseClocked(evt);
		}
	}

	@Override
	public void mouseEntered(java.awt.event.MouseEvent evt) {
	}

	@Override
	public void mouseExited(java.awt.event.MouseEvent evt) {
	}

	@Override
	public void mousePressed(java.awt.event.MouseEvent evt) {
	}

	@Override
	public void mouseReleased(java.awt.event.MouseEvent evt) {
	}

	@Override
	public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
		if (evt.getSource() == treeTests) {
			ExportFrame.this.treeTestsValueChanged(evt);
		}
	}// </editor-fold>

	/**
	 * Zapamata si zvoleny objekt v strome sablon/testov.
	 *
	 * @param evt
	 */
	private void treeTestsValueChanged(javax.swing.event.TreeSelectionEvent evt) {
		javax.swing.tree.DefaultMutableTreeNode treeNode =
						(javax.swing.tree.DefaultMutableTreeNode) evt.getPath().getLastPathComponent();
		if (treeNode.getUserObject() instanceof TestTemplate) {
			TestTemplate testTemplate = (TestTemplate) treeNode.getUserObject();
			ArrayList<TestResult> testResults = Exporter.getTestResults(testTemplate);
			Object[][] data = new Object[testResults.size()][testTemplate.getFieldDefs().size() + ADDITIONAL_COLUMNS];
			int i = 0;
			for (TestResult testResult : testResults) {
				data[i] = getTestResultArray(testResult);
				i++;
			}
			setResultsTableModel(data, testTemplate.getFieldDefs().size());
		} else if (treeNode.getUserObject() instanceof FullName) {
			FullName fullName = (FullName) treeNode.getUserObject();
			javax.swing.tree.DefaultMutableTreeNode treeNodeParent =
							(javax.swing.tree.DefaultMutableTreeNode) treeNode.getParent();
			if (treeNodeParent.getUserObject() instanceof TestTemplate) {
				TestTemplate testTemplate = (TestTemplate) treeNodeParent.getUserObject();
				TestResult testResult = Exporter.getTestResult(testTemplate, fullName);
				Object[][] data = new Object[1][testResult.getEvaluation().size() + ADDITIONAL_COLUMNS];
				data[0] = getTestResultArray(testResult);
				setResultsTableModel(data, testResult.getEvaluation().size());
			}
		}
	}

	/**
	 * Otvori save dialog a ulozi do zvoleneho suboru vysledky testov.
	 *
	 * @param evt
	 */
	private void buttonExportTestMouseClicked(java.awt.event.MouseEvent evt) {

		javax.swing.tree.DefaultMutableTreeNode treeNode =
						(javax.swing.tree.DefaultMutableTreeNode) treeTests.getSelectionPath().getLastPathComponent();
		if (!(treeNode.getUserObject() instanceof TestTemplate
						|| treeNode.getUserObject() instanceof FullName)) {
			return;
		}
        exportTestResults(-1);
        JOptionPane.showMessageDialog(parent, "Tabuľka bola exportovaná.", INFO_TITLE, JOptionPane.INFORMATION_MESSAGE);
	}

	/**
	 * Otvori save dialog a ulozi do zvoleneho suboru vysledky zvoleneho pola.
	 *
	 * @param evt
	 */
	private void buttonExportFieldMouseClicked(java.awt.event.MouseEvent evt) {

		if (resultsTable.getSelectedColumn() == 0 || resultsTable.getSelectedColumn() == 1
						|| resultsTable.getSelectedColumn() == resultsTable.getColumnCount() - 1) {
			return;
		}

		javax.swing.tree.DefaultMutableTreeNode treeNode =
						(javax.swing.tree.DefaultMutableTreeNode) treeTests.getSelectionPath().getLastPathComponent();
		if (!(treeNode.getUserObject() instanceof TestTemplate
						|| treeNode.getUserObject() instanceof FullName)) {
			return;
		}
        exportTestResults(resultsTable.getSelectedColumn());
        JOptionPane.showMessageDialog(parent, "Tabuľka bola exportovaná.", INFO_TITLE, JOptionPane.INFORMATION_MESSAGE);
	}

	/**
	 * Otvori save dialog a ulozi do zvoleneho suboru logy z databazy.
	 *
	 * @param evt
	 */
	private void buttonExportLogsMouseClocked(java.awt.event.MouseEvent evt) {
        try {
            Exporter.exportLogs();
            JOptionPane.showMessageDialog(parent,
                    "Záznam činností nad databázou bol exportovaný.", INFO_TITLE,
                    JOptionPane.INFORMATION_MESSAGE);
        } catch (OfflineException ex) {
            Logger.getLogger(ExportFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (PermissionDeniedException e) {
            JOptionPane.showMessageDialog(parent,
                    PERMISSION_EXCEPTION_MSG, ERROR_TITLE,
                    JOptionPane.ERROR_MESSAGE);
        } catch (DatabaseException e) {
            JOptionPane.showMessageDialog(parent, DB_EXCEPTION_MSG,
                    ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
        } catch (IOException e) {
            JOptionPane.showMessageDialog(parent, IO_EXCEPTION_MSG,
                    ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
        }
	}

	/**
	 * Vola funkcie Exportera, ktore vykonaju export vysledkov pre pole field do
	 * suboru s nazovm filename.
	 *
	 * @param field Index exportovaneho pola.
	 * @param filename Meno suboru, do ktoreho si uzivatel praje ulozit data.
	 */
	private void exportTestResults(final int field) {
		if (!(field == -1 || (field >= 2 && field < resultsTable.getColumnCount() - 1))) {
			return;
		}
		javax.swing.tree.DefaultMutableTreeNode treeNode =
						(javax.swing.tree.DefaultMutableTreeNode) treeTests.getSelectionPath().getLastPathComponent();
		if (treeNode.getUserObject() instanceof TestTemplate) {
			TestTemplate testTempate = (TestTemplate) treeNode.getUserObject();
			try {
				if (field == -1) {
					Exporter.exportTestResults(testTempate);
				} else {
					Exporter.exportFieldResults(testTempate, field);
				}

			} catch (IOException e) {
				System.out.println("smola proste...");
			}
		} else if (treeNode.getUserObject() instanceof FullName) {
			FullName fullName = (FullName) treeNode.getUserObject();
			javax.swing.tree.DefaultMutableTreeNode treeNodeParent =
							(javax.swing.tree.DefaultMutableTreeNode) treeNode.getParent();
			if (treeNodeParent.getUserObject() instanceof TestTemplate) {
				TestTemplate testTemplate = (TestTemplate) treeNodeParent.getUserObject();
				TestResult testResult = Exporter.getTestResult(testTemplate, fullName);
				try {
					if (field == -1) {
						Exporter.exportTestResult(testResult);
					} else {
						// nie je implementovane exportovanie jedineho pola pre jediny test,
					}
				} catch (IOException ex) {
					System.out.println("smola proste...");
				}
			}
		}
	}

	/**
	 * Konvertuje vysledok testu na pole objektov vkladanych do tabulky.
	 *
	 * @param testResult Objekt z vyslekom testu, ktory sa ma skonvertovat.
	 * @return Pole objektov vytvorene z parametrov objektu testResult.
	 */
	private Object[] getTestResultArray(TestResult testResult) {
		Object[] data = new Object[testResult.getEvaluation().size() + ADDITIONAL_COLUMNS];
		data[0] = testResult.getEvaluator();
		data[1] = testResult.getStudent();
		ArrayList<Integer> evaluation = testResult.getEvaluation();
		int i = 2;
		int total = 0;
		for (int e : evaluation) {
			total += e;
			data[i] = e;
			i++;
		}
		data[i] = total;
		return data;
	}

	/**
	 * Vytvori tabulku z vysledkov testov.
	 *
	 * @param data Dvojrozmerne pole objektov vkladanych do tabulky.
	 * @param defCount Pocet definovanych poli testu.
	 */
	private void setResultsTableModel(Object[][] data, final int defCount) {
		String[] tableCols = new String[defCount + ADDITIONAL_COLUMNS];
		tableCols[0] = "Hodnotitel";
		tableCols[1] = "Student";
		for (int i = 2; i < tableCols.length - 1; i++) {
			tableCols[i] = "Úloha " + (i - 1);
		}
		tableCols[tableCols.length - 1] = "Spolu";
		resultsTable.setModel(new javax.swing.table.DefaultTableModel(data, tableCols));
		resultsTable.setAutoCreateRowSorter(true);
	}

	/**
	 * Vytvori strom sablon a testov.
	 */
	private void generateTestTree() {
		// root
		javax.swing.tree.DefaultMutableTreeNode treeNodeRoot = new javax.swing.tree.DefaultMutableTreeNode("Testy");
		ArrayList<TestTemplate> templates = Exporter.getTestTemplates();
		for (TestTemplate templ : templates) {
			javax.swing.tree.DefaultMutableTreeNode treeNodeTemplate = new javax.swing.tree.DefaultMutableTreeNode(templ);
			ArrayList<TestResult> results = Exporter.getTestResults(templ);
			HashSet<FullName> students = new HashSet<>();
			for (TestResult result : results) {
				students.add(result.getStudent());
			}
			for (FullName studentName : students) {
				javax.swing.tree.DefaultMutableTreeNode treeNodeResult = new javax.swing.tree.DefaultMutableTreeNode(studentName);
				treeNodeTemplate.add(treeNodeResult);
			}
			treeNodeRoot.add(treeNodeTemplate);
		}
		treeTests.setModel(new javax.swing.tree.DefaultTreeModel(treeNodeRoot));
		treeTests.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		treeTests.setSelectionRow(0);
	}
}
